#region MIT License

/*
 *  Copyright (c) 2010 Nathan Palmer
 *  http://www.nathanpalmer.com/
 * 
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 * 
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 * 
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */

#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Common.Logging;
using MetaSource.Command;
using NLog;
using Quartz;
using SimpleScheduler.Core.Domain;
using LogLevel = NLog.LogLevel;
using LogManager = NLog.LogManager;

namespace SimpleScheduler.Job
{
    public class MultiTaskJob : IStatefulJob, IInterruptableJob
    {
        private Logger log;
        private bool interrupted = false;

        public MultiTaskJob()
        {
            log = LogManager.GetLogger(GetType().ToString());
        }

        public void Execute(JobExecutionContext context)
        {
            JobDataMap data = context.MergedJobDataMap;
            interrupted = false;

            if (context.JobDetail.JobDataMap["TaskResults"] == null)
                context.JobDetail.JobDataMap["TaskResults"] = new Dictionary<string, TaskResult>();


            var tasks = (IList<Task>) data.Get("Tasks");
            var taskResults = (Dictionary<string, TaskResult>) context.JobDetail.JobDataMap["TaskResults"];

            foreach (var task in tasks)
            {
                try
                {
                    if (!taskResults.ContainsKey(task.Name))
                    {
                        taskResults.Add(task.Name, new TaskResult());
                    }

                    context.Put("Name", task.Name);

                    foreach (var property in task.Properties)
                    {
                        context.Put(property.Name, property.Value);
                    }

                    IInterruptableJob job = null;

                    if (task.Type == null) throw new Exception();

                    if (Type.GetType(task.Type) == typeof(CommandLineJob))
                    {
                        job = new CommandLineJob();                        
                    }
                    else if (Type.GetType(task.Type) == typeof(DoNothingJob))
                    {
                        job = new DoNothingJob();
                    }

                    ThreadStart starter =
                        delegate
                            {
                                try
                                {
                                    job.Execute(context);
                                }
                                catch (ThreadAbortException)
                                {
                                    // Interrupt the running job
                                    job.Interrupt();
                                    // Wait for a second and a half for it to stop
                                    Thread.Sleep(1500);
                                }
                            };
                    
                    Thread thread = new Thread(starter);
                    thread.Start();

                    while (thread.ThreadState != System.Threading.ThreadState.Stopped)
                    {
                        if (interrupted)
                        {
                            thread.Abort();
                            return;
                        }

                        Thread.Sleep(1000);
                    }

                    var taskResult = new TaskResult
                                         {
                                             Name = task.Name,
                                             Status = context.JobDetail.JobDataMap["TaskResult"] as String ?? "Unknown",
                                             Output = context.JobDetail.JobDataMap["TaskOutput"] as String ?? ""
                                         };
                    taskResults[task.Name] = taskResult;
                }
                catch (Exception)
                {
                    // Log and continue
                }
            }
        }

        public void Interrupt()
        {
            interrupted = true;
        }
    }
}